﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    using System.ServiceModel.DomainServices;

    [DebuggerDisplay("Type = {_type.Name}")]
    internal sealed class MetaType
    {
        private IEnumerable<System.Type> _childTypes = new List<System.Type>();
        private bool _hasComplexMembers;
        private bool _hasComposition;
        private bool _isComplex;
        private Dictionary<string, MetaMember> _metaMembers = new Dictionary<string, MetaMember>();
        [ThreadStatic]
        private static Dictionary<System.Type, MetaType> _metaTypes;
        private bool _requiresValidation;
        private bool _shouldRoundtripOriginal;
        private System.Type _type;
        private MetaMember _versionMember;

        private MetaType(System.Type type)
        {
            IEnumerable<PropertyInfo> enumerable = from p in type.GetProperties(MemberBindingFlags)
                where p.GetIndexParameters().Length == 0
                orderby p.Name
                select p;
            this._isComplex = TypeUtility.IsComplexType(type);
            bool flag = false;
            foreach (PropertyInfo info in enumerable)
            {
                MetaMember metaMember = new MetaMember(this, info) {
                    IsCollection = TypeUtility.IsSupportedCollectionType(info.PropertyType)
                };
                if ((info.GetGetMethod() != null) && (info.GetSetMethod() != null))
                {
                    bool flag2 = TypeUtility.IsPredefinedType(info.PropertyType);
                    bool flag3 = TypeUtility.IsSupportedComplexType(info.PropertyType);
                    metaMember.IsDataMember = flag2 || flag3;
                    metaMember.IsComplex = flag3;
                    if (flag3)
                    {
                        this._hasComplexMembers = true;
                    }
                }
                if (info.GetGetMethod() != null)
                {
                    metaMember.RequiresValidation = info.GetCustomAttributes(typeof(ValidationAttribute), true).Length > 0;
                }
                if (info.GetCustomAttributes(typeof(AssociationAttribute), false).Length > 0)
                {
                    metaMember.IsAssociationMember = true;
                }
                bool flag4 = info.GetCustomAttributes(typeof(KeyAttribute), false).Length > 0;
                if (flag4)
                {
                    metaMember.IsKeyMember = true;
                }
                if (info.GetCustomAttributes(typeof(CompositionAttribute), false).Length > 0)
                {
                    this._hasComposition = true;
                }
                if (IsRoundtripMember(metaMember))
                {
                    if ((info.GetCustomAttributes(typeof(TimestampAttribute), false).Length != 0) && (info.GetCustomAttributes(typeof(ConcurrencyCheckAttribute), false).Length != 0))
                    {
                        this._versionMember = metaMember;
                    }
                    else if (!flag4)
                    {
                        flag = true;
                    }
                    metaMember.IsRoundtripMember = true;
                }
                metaMember.EditableAttribute = (EditableAttribute) info.GetCustomAttributes(typeof(EditableAttribute), false).SingleOrDefault<object>();
                this._metaMembers.Add(info.Name, metaMember);
            }
            if ((this._versionMember != null) && !flag)
            {
                this._shouldRoundtripOriginal = false;
            }
            else
            {
                this._shouldRoundtripOriginal = true;
            }
            if (this._hasComposition)
            {
                this._childTypes = (from p in type.GetProperties(MemberBindingFlags)
                    where p.GetCustomAttributes(typeof(CompositionAttribute), false).Any<object>()
                    select TypeUtility.GetElementType(p.PropertyType)).ToArray<System.Type>();
            }
            this._type = type;
            this.CalculateAttributesRecursive(type, new HashSet<System.Type>());
        }

        private void CalculateAttributesRecursive(System.Type type, HashSet<System.Type> visited)
        {
            if (visited.Add(type))
            {
                if (!this._requiresValidation)
                {
                    this._requiresValidation = type.GetCustomAttributes(typeof(ValidationAttribute), true).Length > 0;
                }
                foreach (PropertyInfo info in from p in type.GetProperties(MemberBindingFlags)
                    where p.GetIndexParameters().Length == 0
                    orderby p.Name
                    select p)
                {
                    if (!this._requiresValidation)
                    {
                        this._requiresValidation = info.GetCustomAttributes(typeof(ValidationAttribute), true).Length > 0;
                    }
                    if (TypeUtility.IsSupportedComplexType(info.PropertyType))
                    {
                        System.Type elementType = TypeUtility.GetElementType(info.PropertyType);
                        this.CalculateAttributesRecursive(elementType, visited);
                    }
                }
            }
        }

        public static MetaType GetMetaType(System.Type type)
        {
            MetaType type2 = null;
            if (!MetaTypes.TryGetValue(type, out type2))
            {
                type2 = new MetaType(type);
                MetaTypes[type] = type2;
            }
            return type2;
        }

        private static bool IsRoundtripMember(MetaMember metaMember)
        {
            bool flag = metaMember.Member.DeclaringType.GetCustomAttributes(typeof(RoundtripOriginalAttribute), true).Length > 0;
            if (!metaMember.IsDataMember || metaMember.IsAssociationMember)
            {
                return false;
            }
            if (!flag)
            {
                return (metaMember.Member.GetCustomAttributes(typeof(RoundtripOriginalAttribute), false).Length != 0);
            }
            return true;
        }

        public IEnumerable<PropertyInfo> AssociationMembers
        {
            get
            {
                return (from m in this._metaMembers.Values
                    where m.IsAssociationMember
                    select m.Member);
            }
        }

        public IEnumerable<System.Type> ChildTypes
        {
            get
            {
                return this._childTypes;
            }
        }

        public IEnumerable<MetaMember> DataMembers
        {
            get
            {
                return (from m in this._metaMembers.Values
                    where m.IsDataMember
                    select m);
            }
        }

        public bool HasComplexMembers
        {
            get
            {
                return this._hasComplexMembers;
            }
        }

        public bool HasComposition
        {
            get
            {
                return this._hasComposition;
            }
        }

        public bool IsComplex
        {
            get
            {
                return this._isComplex;
            }
        }

        public MetaMember this[string memberName]
        {
            get
            {
                MetaMember member = null;
                if (this._metaMembers.TryGetValue(memberName, out member))
                {
                    return member;
                }
                return null;
            }
        }

        public IEnumerable<PropertyInfo> KeyMembers
        {
            get
            {
                return (from m in this._metaMembers.Values
                    where m.IsKeyMember
                    select m.Member);
            }
        }

        internal static BindingFlags MemberBindingFlags
        {
            get
            {
                return (BindingFlags.Public | BindingFlags.Instance);
            }
        }

        public IEnumerable<MetaMember> Members
        {
            get
            {
                return this._metaMembers.Values;
            }
        }

        private static Dictionary<System.Type, MetaType> MetaTypes
        {
            get
            {
                if (_metaTypes == null)
                {
                    _metaTypes = new Dictionary<System.Type, MetaType>();
                }
                return _metaTypes;
            }
        }

        public bool RequiresValidation
        {
            get
            {
                return this._requiresValidation;
            }
        }

        public IEnumerable<PropertyInfo> RoundtripMembers
        {
            get
            {
                return (from m in this._metaMembers.Values
                    where m.IsRoundtripMember
                    select m.Member);
            }
        }

        public bool ShouldRoundtripOriginal
        {
            get
            {
                return this._shouldRoundtripOriginal;
            }
        }

        public System.Type Type
        {
            get
            {
                return this._type;
            }
        }

        public IEnumerable<ValidationAttribute> ValidationAttributes
        {
            get
            {
                return this._type.GetCustomAttributes(true).OfType<ValidationAttribute>();
            }
        }

        public MetaMember VersionMember
        {
            get
            {
                return this._versionMember;
            }
        }
    }
}

